﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="MainViewModel.cs" company="">
//   
// </copyright>
// <summary>
//   Defines the MainViewModel type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace F5.BigIp.LocalTrafficManager.UI.ViewModels
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    using System.Windows;
    using System.Windows.Input;
    using System.Windows.Threading;

    using F5.BigIp.LocalTrafficManager.Interfaces;
    using F5.BigIp.LocalTrafficManager.UI.Commands;
    using F5.BigIp.LocalTrafficManager.UI.Views;

    /// <summary>
    ///     The main window view model.
    /// </summary>
    public class MainViewModel : NotifyPropertyChanged, IMainViewModel
    {
        private readonly IViewFactory viewFactory;

        private readonly IPoolMemberService poolMemberService;

        #region Fields

        /// <summary>
        ///     The LoadBalancers.
        /// </summary>
        private ICollection<LoadBalancer> loadBalancers;

        /// <summary>
        ///     The disable selected pool members.
        /// </summary>
        private ICommand disableCommand;

        /// <summary>
        ///     The enable selected pool members.
        /// </summary>
        private ICommand enableCommand;

        /// <summary>
        ///     The exit command.
        /// </summary>
        private ICommand exitCommand;

        /// <summary>
        ///     The force offline command.
        /// </summary>
        private ICommand forceOfflineCommand;

        /// <summary>
        ///     The hide pools.
        /// </summary>
        private bool hidePools;

        /// <summary>
        ///     The is busy.
        /// </summary>
        private bool isBusy;

        /// <summary>
        ///     The load LoadBalancers command.
        /// </summary>
        private ICommand loadDevicesCommand;

        /// <summary>
        ///     The load pool members command.
        /// </summary>
        private ICommand loadPoolMembersCommand;

        /// <summary>
        ///     The load LoadBalancer pools command.
        /// </summary>
        private ICommand loadPoolsCommand;

        /// <summary>
        ///     The pool member selection changed.
        /// </summary>
        private ICommand poolMemberSelectionChanged;

        /// <summary>
        ///     The refresh pool members command.
        /// </summary>
        private ICommand refreshPoolMembersCommand;

        /// <summary>
        ///     The selected LoadBalancer.
        /// </summary>
        private LoadBalancer selectedLoadBalancer;

        /// <summary>
        ///     The selected pool.
        /// </summary>
        private IPool selectedPool;

        /// <summary>
        ///     The selected pool members.
        /// </summary>
        private IList<IPoolMember> selectedPoolMembers;

        /// <summary>
        ///     The set update speed command.
        /// </summary>
        private ICommand setUpdateSpeedCommand;

        /// <summary>
        ///     The status.
        /// </summary>
        private string status;

        /// <summary>
        ///     The update speed.
        /// </summary>
        private int updateSpeed;

        /// <summary>
        ///     The add LoadBalancer command.
        /// </summary>
        private ICommand addDeviceCommand;

        /// <summary>
        ///     The remove LoadBalancer command.
        /// </summary>
        private ICommand removeDeviceCommand;

        /// <summary>The pools.</summary>
        private IEnumerable<IPool> pools;

        /// <summary>The pool members.</summary>
        private IList<IPoolMember> poolMembers;

        #endregion

        #region Constructors and Destructors

        /// <summary>
        ///     Design Mode.
        ///     Initializes a new instance of the <see cref="MainViewModel" /> class.
        /// </summary>
        public MainViewModel()
        {
        }

        /// <summary>
        ///     Run Time.
        ///     Initializes a new instance of the <see cref="MainViewModel" /> class.
        /// </summary>
        public MainViewModel(IMainWindow window, IViewFactory viewFactory, IPoolMemberService poolMemberService)
        {
            if (window == null)
            {
                throw new ArgumentNullException("window");
            }

            if (viewFactory == null)
            {
                throw new ArgumentNullException("viewFactory");
            }

            if (poolMemberService == null)
            {
                throw new ArgumentNullException("poolMemberService");
            }

            this.viewFactory = viewFactory;

            this.poolMemberService = poolMemberService;

            this.Window = window;

            this.Window.DataContext = this;

            this.UpdateSpeed = 5;

            this.Timer = new DispatcherTimer { Interval = new TimeSpan(0, 0, this.UpdateSpeed) };

            this.Timer.Tick += this.OnTimerTick;
        }

        #endregion

        #region Public Properties

        public IWindow Window { get; set; }

        /// <summary>
        ///     Gets or sets the LoadBalancers.
        /// </summary>
        public ICollection<LoadBalancer> LoadBalancers
        {
            get
            {
                return this.loadBalancers;
            }
            set
            {
                this.loadBalancers = value;
                this.OnPropertyChanged();
            }
        }

        /// <summary>
        /// Gets or sets the pools.
        /// </summary>
        public IEnumerable<IPool> Pools
        {
            get
            {
                return this.pools;
            }
            set
            {
                this.pools = value;
                this.OnPropertyChanged();
            }
        }

        /// <summary>
        /// Gets or sets the pool members.
        /// </summary>
        public IList<IPoolMember> PoolMembers
        {
            get
            {
                return this.poolMembers;
            }
            set
            {
                this.poolMembers = value;
                this.OnPropertyChanged();
            }
        }

        /// <summary>
        ///     Gets or sets the selected LoadBalancer.
        /// </summary>
        public LoadBalancer SelectedLoadBalancer
        {
            get
            {
                return this.selectedLoadBalancer;
            }
            set
            {
                this.selectedLoadBalancer = value;
                this.OnPropertyChanged();
            }
        }

        /// <summary>
        ///     Gets or sets the selected pool members.
        /// </summary>
        public IList<IPoolMember> SelectedPoolMembers
        {
            get
            {
                return this.selectedPoolMembers;
            }
            set
            {
                this.selectedPoolMembers = value;
                this.OnPropertyChanged();
            }
        }

        /// <summary>
        ///     Gets or sets the selected pool.
        /// </summary>
        public IPool SelectedPool
        {
            get
            {
                return this.selectedPool;
            }
            set
            {
                this.selectedPool = value;
                this.OnPropertyChanged();
            }
        }

        /// <summary>
        ///     Gets or sets the status.
        /// </summary>
        public string Status
        {
            get
            {
                return this.status;
            }
            set
            {
                this.status = value;
                this.OnPropertyChanged();
            }
        }

        /// <summary>
        ///     Gets the timer.
        /// </summary>
        public DispatcherTimer Timer { get; private set; }

        /// <summary>
        ///     Gets the title.
        /// </summary>
        public static string Title
        {
            get
            {
                return string.Format("F5 BIG-IP Local Traffic Manager {0}", Assembly.GetEntryAssembly().GetName().Version);
            }
        }

        /// <summary>
        ///     Gets or sets the update speed.
        /// </summary>
        public int UpdateSpeed
        {
            get
            {
                return this.updateSpeed;
            }
            set
            {
                this.updateSpeed = value;
                this.OnPropertyChanged();
            }
        }

        /// <summary>
        ///     Gets or sets a value indicating whether is busy.
        /// </summary>
        public bool IsBusy
        {
            get
            {
                return this.isBusy;
            }
            set
            {
                this.isBusy = value;
                this.OnPropertyChanged();
            }
        }

        /// <summary>
        ///     Gets or sets a value indicating whether hide pools.
        /// </summary>
        public bool HidePools
        {
            get
            {
                return this.hidePools;
            }
            set
            {
                this.hidePools = value;
                this.OnPropertyChanged();
            }
        }

        #endregion

        #region Commands

        /// <summary>
        ///     Gets the disable selected pool members.
        /// </summary>
        public ICommand DisableCommand
        {
            get
            {
                return this.disableCommand ?? (this.disableCommand = new DisablePoolMembers(this.poolMemberService));
            }
        }

        /// <summary>
        ///     Gets the enable selected pool members.
        /// </summary>
        public ICommand EnableCommand
        {
            get
            {
                return this.enableCommand ?? (this.enableCommand = new EnablePoolMembers(this.poolMemberService));
            }
        }

        /// <summary>
        ///     Gets the exit command.
        /// </summary>
        public ICommand ExitCommand
        {
            get
            {
                return this.exitCommand ?? (this.exitCommand = new RelayCommand(k => Application.Current.Shutdown()));
            }
        }

        /// <summary>
        ///     Gets the take pool members offline command.
        /// </summary>
        public ICommand ForceOfflineCommand
        {
            get
            {
                return this.forceOfflineCommand ?? (this.forceOfflineCommand = new ForcePoolMembersOffline(this.poolMemberService));
            }
        }

        /// <summary>
        ///     Gets or sets the hide pools command.
        /// </summary>
        public ICommand HidePoolsCommand { get; set; }

        /// <summary>
        ///     Gets the load LoadBalancers command.
        /// </summary>
        public ICommand LoadDevicesCommand
        {
            get
            {
                return this.loadDevicesCommand ?? (this.loadDevicesCommand = new LoadDevices(this));
            }
        }

        /// <summary>
        ///     Gets the load pool members command.
        /// </summary>
        public ICommand LoadPoolMembersCommand
        {
            get
            {
                return this.loadPoolMembersCommand ?? (this.loadPoolMembersCommand = new LoadPoolMembers(this, this.poolMemberService));
            }
        }

        /// <summary>
        ///     Gets the load pools command.
        /// </summary>
        public ICommand LoadPoolsCommand
        {
            get
            {
                return this.loadPoolsCommand ?? (this.loadPoolsCommand = new LoadPools(this));
            }
        }

        /// <summary>
        ///     Gets the pool member selection changed.
        /// </summary>
        public ICommand PoolMemberSelectionChanged
        {
            get
            {
                return this.poolMemberSelectionChanged ?? (this.poolMemberSelectionChanged = new RelayCommand(
                                                                                                 k =>
                                                                                                 {
                                                                                                     var items =
                                                                                                         k as IList;

                                                                                                     if (items
                                                                                                         != null)
                                                                                                     {
                                                                                                         this
                                                                                                             .SelectedPoolMembers
                                                                                                             =
                                                                                                             items
                                                                                                                 .Cast
                                                                                                                 <
                                                                                                                     IPoolMember
                                                                                                                     >
                                                                                                                 ()
                                                                                                                 .ToList
                                                                                                                 ();
                                                                                                     }
                                                                                                 }));
            }
        }

        /// <summary>
        ///     Gets the refresh pool members command.
        /// </summary>
        public ICommand RefreshPoolMembersCommand
        {
            get
            {
                return this.refreshPoolMembersCommand ?? (this.refreshPoolMembersCommand = new RefreshPoolMembers(this, this.poolMemberService));
            }
        }

        /// <summary>
        ///     Gets the add LoadBalancer command.
        /// </summary>
        public ICommand AddDeviceCommand
        {
            get
            {
                return this.addDeviceCommand
                    ?? (this.addDeviceCommand = new AddDevice(this));
            }
        }

        /// <summary>
        /// Gets the remove LoadBalancer command.
        /// </summary>
        public ICommand RemoveDeviceCommand
        {
            get
            {
                return this.removeDeviceCommand
                    ?? (this.removeDeviceCommand = new RemoveDevice(this));
            }
        }

        /// <summary>
        ///     Gets the set update speed command.
        /// </summary>
        public ICommand SetUpdateSpeedCommand
        {
            get
            {
                return this.setUpdateSpeedCommand ?? (this.setUpdateSpeedCommand = new SetUpdateSpeed(this));
            }
        }

        #endregion

        #region Methods

        public void AddLoadBalancer(LoadBalancer loadBalancer)
        {
            if (loadBalancer != null)
            {
                this.loadBalancers.Add(loadBalancer);
            }
        }

        /// <summary>The on timer tick.</summary>
        /// <param name="sender">The sender.</param>
        /// <param name="args">The args.</param>
        private void OnTimerTick(object sender, EventArgs args)
        {
            if (this.RefreshPoolMembersCommand.CanExecute(this.SelectedPool))
            {
                this.RefreshPoolMembersCommand.Execute(this.SelectedPool);
            }
        }

        #endregion
    }
}